package com.wei.czz.framework.game.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.dto.common.NameValue;
import com.wei.czz.common.dto.game.FlowDto;
import com.wei.czz.common.dto.game.GameUserDto;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.po.game.GameUserPo;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.tool.PageQuery;
import com.wei.czz.common.utils.SecurityUtils;
import com.wei.czz.framework.common.handler.redis.RedisHashHandler;
import com.wei.czz.common.vo.common.UpdateStatusVo;
import com.wei.czz.common.vo.game.DeleteGameUserVo;
import com.wei.czz.common.vo.game.GameUserFormVo;
import com.wei.czz.common.vo.game.GameUserVo;
import com.wei.czz.framework.admin.service.UserService;
import com.wei.czz.framework.common.service.AsyncService;
import com.wei.czz.framework.game.entity.GameUserFlowEntity;
import com.wei.czz.framework.game.service.GameUserFlowService;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.wei.czz.framework.game.dao.GameUserDao;
import com.wei.czz.framework.game.entity.GameUserEntity;
import com.wei.czz.framework.game.service.GameUserService;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2023-03-16 11:36:47
 * className: GameUserServiceImpl 游戏用户请求服务接口实现类
 * version: 1.0
 * description:
 */
@Service("gameUserService")
@AllArgsConstructor
public class GameUserServiceImpl extends ServiceImpl<GameUserDao, GameUserEntity> implements GameUserService {

    private static final Logger log = LoggerFactory.getLogger(GameUserServiceImpl.class);

    private final UserService userService;

    private final GameUserFlowService gameUserFlowService;

    private final RedisHashHandler redisHashHandler;

    private final AsyncService asyncService;

    @Override
    public void saveGameUser(GameUserVo gameUserVo) {

        // 获取正在保存游戏用户的用户主键
        Long optUserId = SecurityUtils.getUserId();
        Date date = new Date();

        GameUserEntity gameUser = new GameUserEntity();
        // 属性赋值
        gameUser.setUserId(gameUserVo.getUserId())
                .setGameId(gameUserVo.getGameId())
                .setGameTotalNum(gameUserVo.getGameTotalNum())
                .setGameUseNum(0)
                .setStatus(CommonEnum.ZERO.getValue())
                .setDeleteFlag(CommonEnum.ZERO.getValue())
                .setUpdateTime(date)
                .setUpdateUser(optUserId)
                .setCreateTime(date)
                .setCreateUser(optUserId)
                .setRemark(gameUserVo.getRemark());
        // 插入数据
        baseMapper.insert(gameUser);
        log.info("游戏用户数据插入完成");

        asyncService.execute(() -> {
            // 记录新增游戏用户流水
            String content = "可用游戏次数【" + gameUser.getGameTotalNum() + '】';
            // 记录用户流水
            gameUserFlowService.saveGameUserFlow(gameUserVo.getUserId(), gameUserVo.getGameId(), "添加游戏用户", content, optUserId);
        });

        // 增加缓存
        Long gameTotalNum = redisHashHandler.increment(RedisConstant.GAME_USER_MAP + gameUserVo.getGameId(), gameUserVo.getUserId().toString(), gameUser.getGameTotalNum());
        log.info("缓存返回的结果。gameTotalNum={}", gameTotalNum);
    }

    @Override
    public PageDto<GameUserDto> pageGameUserList(GameUserFormVo gameUserFormVo) {

        // 分页对象构造
        Page<GameUserEntity> page = PageQuery.initPage(gameUserFormVo);

        baseMapper.pageGameUserList(page, gameUserFormVo, CommonEnum.ZERO.getValue());

        List<GameUserEntity> gameUserList = page.getRecords();
        if (gameUserList.isEmpty()) {
            return new PageDto<>(Collections.emptyList(), page.getTotal(), gameUserFormVo.getPage(), gameUserFormVo.getLimit());
        }

        Set<Long> userIdSet = gameUserList.stream().flatMap(gameUser -> Stream.of(gameUser.getUserId(), gameUser.getCreateUser())).collect(Collectors.toSet());
        Map<Long, String> userNameMap = userService.getNameMap(userIdSet, Function.identity());

        // 数据封装
        List<GameUserDto> gameUserDtoList = gameUserList.stream()
                .map(gameUser -> {
                    GameUserDto gameUserDto = new GameUserDto();
                    // 属性值复制
                    BeanUtils.copyProperties(gameUser, gameUserDto);

                    gameUserDto.setId(gameUser.getId().toString())
                            .setUserId(gameUser.getUserId().toString())
                            .setUsername(userNameMap.get(gameUser.getUserId()))
                            .setCreateUser(userNameMap.get(gameUser.getCreateUser()));

                    return gameUserDto;
                }).collect(Collectors.toList());

        return new PageDto<>(gameUserDtoList, page.getTotal(), gameUserFormVo.getPage(), gameUserFormVo.getLimit());
    }

    @Override
    public List<NameValue<String>> getSimpleGameUserList(Long gameId) {

        Set<Long> userIdSet = baseMapper.getUserIdList(gameId, CommonEnum.ZERO.getValue());

        Map<Long, String> userNameMap = userService.getNameMap(userIdSet, Function.identity());

        return userIdSet.stream()
                .map(userId -> new NameValue<>(userNameMap.get(userId), userId.toString()))
                .collect(Collectors.toList());
    }

    @Override
    public List<FlowDto> getGameUserFlowList(Long id) {

        /*
            获取游戏用户
         */
        GameUserEntity gameUser = baseMapper.selectById(id);
        if (gameUser == null) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "游戏用户不存在，请确认");
        }
        /*
            获取游戏用户流水
         */
        List<GameUserFlowEntity> gameUserFlowList = gameUserFlowService.getGameUserFlowList(gameUser.getUserId(),
                gameUser.getGameId());

        /*
            数据封装
         */
        Set<Long> userIdSet = gameUserFlowList.stream()
                .map(GameUserFlowEntity::getCreateUser)
                .collect(Collectors.toSet());
        Map<Long, String> userNameMap = userService.getNameMap(userIdSet, Function.identity());

        return gameUserFlowList.stream()
                .sorted(Comparator.comparing(GameUserFlowEntity::getId).reversed())
                .map(gameUserFlow -> {
                    FlowDto flowDto = new FlowDto();
                    flowDto.setTitle(gameUserFlow.getTitle())
                            .setContent(gameUserFlow.getContent())
                            .setCreateTime(gameUserFlow.getCreateTime())
                            .setCreateUser(userNameMap.get(gameUserFlow.getCreateUser()));
                    return flowDto;
                })
                .collect(Collectors.toList());
    }

    @Override
    public void incrementGameNum(GameUserVo gameUserVo) {
        // 获取正在增加游戏用户可用游戏次数的用户主键
        Long optUserId = SecurityUtils.getUserId();
        Date date = new Date();

        GameUserEntity gameUser = new GameUserEntity();
        // 属性赋值
        gameUser.setId(gameUserVo.getId())
                .setGameTotalNum(gameUserVo.getGameTotalNum())
                .setUpdateTime(date)
                .setUpdateUser(optUserId);
        // 更新数据
        int count = baseMapper.incrementGameNum(gameUser);
        log.info("增加游戏用户的游戏总次数完成。count={}", count);
        if (count == 0) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "游戏用户不存在，请确认。");
        }
        // 操作记录
        asyncService.execute(() -> {
            // 记录游戏用户增加可用次数流水
            String content = "增加可用次数【" + gameUser.getGameTotalNum() + '】';
            // 记录用户流水
            gameUserFlowService.saveGameUserFlow(gameUser.getUserId(), gameUser.getGameId(),  "增加游戏次数", content, optUserId);
        });

        // 操作缓存
        Long gameTotalNum = redisHashHandler.increment(RedisConstant.GAME_USER_MAP + gameUserVo.getGameId(), gameUser.getUserId().toString(), gameUser.getGameTotalNum());
        log.info("缓存返回的结果。gameTotalNum={}", gameTotalNum);
    }

    @Override
    public void updateGameUserStatus(UpdateStatusVo updateStatusVo) {

        LambdaQueryWrapper<GameUserEntity> gameUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        gameUserLambdaQueryWrapper.select(GameUserEntity::getId, GameUserEntity::getUserId, GameUserEntity::getGameId,
                GameUserEntity::getGameTotalNum, GameUserEntity::getGameUseNum);
        // 匹配条件
        gameUserLambdaQueryWrapper.in(GameUserEntity::getId, updateStatusVo.getIdList())
                .eq(GameUserEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 查询数据
        List<GameUserEntity> gameUserList = baseMapper.selectList(gameUserLambdaQueryWrapper);
        if (gameUserList.isEmpty()) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "游戏用户数据不存在，请务必及时处理");
        }
        if (gameUserList.size() != updateStatusVo.getIdList().size()) {
            log.warn("gameUserList={}", gameUserList);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "游戏用户数据缺失，请务必及时处理");
        }

        // 获取正在更新游戏用户状态的用户主键
        Long optUserId = SecurityUtils.getUserId();

        LambdaUpdateWrapper<GameUserEntity> gameUserLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 更新字段
        gameUserLambdaUpdateWrapper.set(GameUserEntity::getStatus, updateStatusVo.getStatus())
                .set(GameUserEntity::getUpdateTime, new Date())
                .set(GameUserEntity::getUpdateUser, optUserId);
        // 匹配条件
        gameUserLambdaUpdateWrapper.in(GameUserEntity::getId, updateStatusVo.getIdList())
                .eq(GameUserEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 更新数据
        int count = baseMapper.update(null, gameUserLambdaUpdateWrapper);
        log.info("游戏用户状态更新完成。count={}", count);
        if (count == 0) {
            throw new CzzException(ResultEnum.REFRESH.getCode(), "游戏用户数据不存在，请确认");
        }

        Long gameId = gameUserList.get(0).getGameId();

        // 操作记录
        asyncService.execute(() -> {
            StringBuilder sb = new StringBuilder();
            // 记录游戏用户状态变更流水
            sb.append("游戏用户状态变更 ");
            CommonEnum statusEnum = CommonEnum.getStatusEnum(updateStatusVo.getStatus());
            if (statusEnum != null) {
                sb.append("最新状态【").append(statusEnum.getName()).append('】');
            }
            List<Long> userIdList = new ArrayList<>(gameUserList.size());
            for (GameUserEntity gameUser : gameUserList) {
                userIdList.add(gameUser.getUserId());
            }
            // 记录用户流水
            gameUserFlowService.saveGameUserFlow(userIdList, gameId, "修改用户", sb.toString(), optUserId);
        });

        if (CommonEnum.ZERO.getValue().equals(updateStatusVo.getStatus())) {
            /*
                增加缓存
             */
            // list 转 map
            Map<String, Integer> gameUserMap = gameUserList.stream()
                    .filter(gameUser -> gameUser.getGameTotalNum().compareTo(gameUser.getGameUseNum()) > 0)
                    .collect(Collectors.toMap(gameUser -> gameUser.getUserId().toString(), gameUser -> gameUser.getGameTotalNum() - gameUser.getGameUseNum(), (o1, o2) -> o1));
            if (gameUserMap.isEmpty()) {
                log.info("游戏用户的游戏次数已使用完毕，无需添加缓存");
            } else {
                redisHashHandler.putAll(RedisConstant.GAME_USER_MAP + gameId, gameUserMap);
            }
        } else {
            /*
                删除缓存
             */
            String[] userIds = gameUserList.stream().map(GameUserEntity::getUserId).map(Objects::toString).toArray(String[]::new);
            redisHashHandler.delete(RedisConstant.GAME_USER_MAP + gameId, userIds);
        }
    }

    @Override
    public void addUseNum(GameUserPo gameUserPo) {
        int count = baseMapper.addUseNum(gameUserPo.getUserId(), gameUserPo.getGameId(), new Date());
        log.info("增加用户游戏使用次数完成。count={}", count);
    }

    @Override
    public void deleteGameUser(DeleteGameUserVo deleteGameUserVo) {

        // 获取正在删除游戏用户的用户主键
        Long optUserId = SecurityUtils.getUserId();

        LambdaUpdateWrapper<GameUserEntity> gameUserLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 设置字段
        gameUserLambdaUpdateWrapper.set(GameUserEntity::getDeleteFlag, CommonEnum.ONE.getValue())
                .set(GameUserEntity::getUpdateTime, new Date())
                .set(GameUserEntity::getUpdateUser, optUserId);
        // 匹配条件
        gameUserLambdaUpdateWrapper.in(GameUserEntity::getId, deleteGameUserVo.getIdList())
                .eq(GameUserEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 更新数据
        int count = baseMapper.update(null, gameUserLambdaUpdateWrapper);
        log.info("删除游戏用户操作完成。count={}", count);
        if (count == 0) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "游戏用户不存在，请确认");
        }

        asyncService.execute(() -> {
            // 记录用户流水
            gameUserFlowService.saveGameUserFlow(deleteGameUserVo.getUserIdList(), deleteGameUserVo.getGameId(), "删除游戏用户", "", optUserId);
        });

        // 删除缓存
        String[] userIds = deleteGameUserVo.getUserIdList().stream().map(Objects::toString).toArray(String[]::new);
        redisHashHandler.delete(RedisConstant.GAME_USER_MAP + deleteGameUserVo.getGameId(), userIds);
    }
}